home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / ScriptX / Code Samples / autofind / source / grapher.sx < prev    next >
Encoding:
Text File  |  1996-05-21  |  8.6 KB  |  283 lines  |  [TEXT/ttxt]

  1. --<<<
  2. -- Filename: 
  3. --     grapher.sx
  4.  
  5. -- Other Files Required:
  6. --     axisprop.sx, labels.sx, axis.sx, graphable.sx, grphmenu.sx
  7.  
  8. -- Purpose:  
  9. --     Create a Grapher class, a model for graphing objects in a two-dimensional graph.
  10.  
  11. -- Specialized Classes:  
  12. --     Grapher
  13.  
  14. -- Instructions to User: 
  15. --     The Grapher class will graph any object who has an instance variable that matches
  16. --     either the current x-axis property or the y-axis property.  If the object does not
  17. --     have both, it will be graphed at the minimum value on the axis whose property it
  18. --     does not have. 
  19. --     The property mapped on the axis can be changed via a popup menu of object
  20. --     properties.  Axis labels and object positions will then be changed accordingly.
  21. --     This is a model for graphing, divorced from presentation.
  22. --     See vanilla.sx and autograph.sx for examples of how graphing can be wedded
  23. --     to two different types of layout.
  24.  
  25. -- Author:
  26. --      Dionn Stewart, Steve Gano, Steve Mayer, Ray Davis
  27. in module Autofinder
  28.  
  29. class Grapher (TwoDSpace)
  30. instance variables
  31.     xAxis            -- horizontal axis definition and associated labels
  32.     yAxis            -- vertical axis definition and associated labels
  33.     objectList        -- the list of objects to graph or graphed
  34.     propertyList    -- list of graphable properties 
  35.     travelMaster    -- masterclock for all the travelers
  36.     travelDuration    -- duration of interpolation 
  37.     propertyMenu    -- menu of the propertylist
  38.     background
  39.     control
  40. end
  41.  
  42. method init self {class Grapher} #rest args #key \
  43.      boundary:(undefined) \
  44.      background:(undefined) \
  45.      xAxis: \
  46.      yAxis: \
  47.      propertyMenu: \
  48.      propertyList:(new Array) \
  49.      travelMaster:(new Clock) \
  50.      travelDuration:(12) ->
  51. (
  52.     if boundary = undefined do
  53.         boundary := background.bbox
  54.     apply nextMethod self boundary:boundary args
  55.  
  56.     -- if new properties are defined on the axes, add them to the menu
  57.     if (xAxis.property <> undefined) and \
  58.         (not (isMember propertyList xAxis.property)) do
  59.              append propertyList xAxis.property
  60.     if (yAxis.property <> undefined) and \
  61.         (not (isMember propertyList yAxis.property)) do
  62.              append propertyList yAxis.property
  63.  
  64.     -- Attach the menu to the invokers 
  65.     xAxis.axisLabel.menu:= propertyMenu
  66.     yAxis.axisLabel.menu:= propertyMenu    
  67.     
  68.     self.background := background
  69.     prepend self background
  70.     self.xAxis:= xAxis; prepend self xAxis
  71.     self.yAxis:= yAxis; prepend self yAxis
  72.     self.propertyList := propertyList
  73.     self.propertyMenu := propertyMenu
  74.  
  75.     -- set up the clock that will control the traveling of all the objects
  76.     travelMaster.rate:= 0
  77.     self.travelMaster:= travelMaster
  78.     self.travelMaster.scale:= 1
  79.     self.travelDuration:= travelDuration
  80.     self
  81. )
  82.  
  83. method afterInit self {class Grapher} #rest args #key \
  84.     objectList:(new Array) ->
  85. (
  86.     apply nextMethod self args
  87.     
  88.     -- Init variables
  89.     self.objectList := objectList
  90.  
  91.     -- Create controllers
  92.     local dc := new DragController space:self wholespace:true
  93.     
  94.     -- Add a RowColumnController to the graph so when a group of objects get added
  95.     -- they form a nice row before they are graphed
  96.     local rc:= new RowColumnController space:self numColumns:6 numRows:5 layoutOrder:@rowMajor
  97.     rc.defaultHeight := @highest
  98.     rc.defaultWidth := @widest
  99.     
  100.     self.control := #(dc, rc)
  101.     
  102.     -- Add the properties
  103.     for i in self.propertyList do
  104.         addPropertytoMenu self i
  105.  
  106.     -- Set up the axis labels
  107.     if self.propertyList.size > 0 do
  108.     (
  109.         if self.xAxis.property = undefined do
  110.             changeProperty self.xAxis self.propertyList[1]
  111.         if (self.propertyList.size > 1) and (self.yAxis.property = undefined) do
  112.             changeProperty self.yAxis self.propertyList[2]
  113.     )
  114.     
  115.     -- If we were given a group of initial objects, then position them on
  116.     -- the graph.
  117. --    if (size objectList) > 0 do
  118. --        addObjectsToGraph self objectList
  119.         
  120.     self
  121. )
  122.  
  123. method leaveScene self {class Grapher} ->
  124. (
  125.     for i in self.control do
  126.         i.space := undefined
  127.     emptyout self.control
  128.     
  129.     emptyout self
  130.     makePurgeable self.background
  131.     self.background := self.xAxis := self.yAxis := undefined
  132. )
  133.  
  134. -- Position the labels on the graph in the default fashion.
  135. method placeLabels self {class Grapher} ->
  136. (
  137.     local orgx := self.xAxis.origin
  138.     local orgy := self.yAxis.origin
  139.     
  140.     -- generically places the minLabel at the origin, the maxLabel at the right
  141.     -- end and the axisLabel in the center below the axis line
  142.     self.xAxis.minLabel.x:= orgx
  143.     self.xAxis.minLabel.y:= orgy + 5
  144.     self.xAxis.maxLabel.x:= orgx + self.xAxis.length - self.xAxis.maxLabel.width
  145.     self.xAxis.maxLabel.y:= orgy + 5
  146.     self.xAxis.axisLabel.x:= orgx + ((self.xAxis.length/2) - (self.xAxis.axisLabel.width/2)) - 10
  147.     self.xAxis.axisLabel.y:= orgy + 25
  148.  
  149.     -- generically places the minLabel at the origin, the maxLabel at the top
  150.     -- end and the axisLabel in the center, all to the left of the axis line
  151.     local labelx := orgx - 5
  152.     self.yAxis.minLabel.x:= labelx - self.yAxis.minLabel.width
  153.     self.yAxis.minLabel.y:= orgy - self.yAxis.minLabel.height
  154.     self.yAxis.maxLabel.x:= labelx - self.yAxis.maxLabel.width
  155.     self.yAxis.maxLabel.y:= orgy - self.yAxis.length
  156.     self.yAxis.axisLabel.x:= labelx - self.yAxis.axisLabel.width - 16
  157.     self.yAxis.axisLabel.y:= orgy - (self.yAxis.length/2) -
  158. (self.yAxis.axisLabel.height/2)
  159.     undefined
  160. )
  161.  
  162. method addPropertyToMenu self {class Grapher} prop ->
  163. (
  164.     -- add the pushbutton to the menu
  165.     addPropertyToMenu self.propertyMenu prop
  166.  
  167.     if not (isMember self.propertyList prop) do append self.propertyList prop
  168. )
  169.  
  170. -- Add a group of objects to the grapher, starting them off in a tidy row
  171. method addObjectsToGraph self {class Grapher} objList ->
  172. (
  173.     local rc := (chooseOne self.controllers \ 
  174.             (rc dummy -> isAKindOf rc RowColumnController) undefined)
  175.     local pos := 1
  176.     
  177.     foreach objList (obj arg ->
  178.             pos := pos + 1
  179.             addObjectToGraph self obj position:pos
  180.             -- Add the object to the RowColumn controller
  181.             append rc obj
  182.         ) undefined
  183.     undefined
  184. )
  185.  
  186. -- subclasses or instances can override this (must call nextMethod though)
  187. -- if they want to do anything else when a graphable object is added 
  188. -- to the grapher
  189. method addObjectToGraph self {class Grapher} obj #key position:->
  190. (
  191.     append self.objectList obj
  192.     if position = unsupplied then
  193.         prepend self obj
  194.     else 
  195.         addNth self position obj
  196.     if obj.travelClock.masterclock = undefined do
  197.         obj.travelClock.masterClock := self.travelMaster
  198.     undefined
  199. )
  200.  
  201. -- subclasses or instances can override this (must call nextMethod though)
  202. -- if they want to do anything else when a graphable object is removed 
  203. -- from the grapher
  204. method removeFromGraph self {class Grapher} obj->
  205. (
  206.     deleteone self obj
  207.     deleteone self.objectList obj
  208.     undefined
  209. )
  210.  
  211. method graphObjects self {class Grapher} objList #key duration: ->
  212. (
  213.     -- Remove all objects from the RowColumn controller for graphing.
  214.     emptyout (chooseOne self.controllers \ 
  215.              (rc dummy -> isAKindOf rc RowColumnController) undefined)
  216.     
  217.     self.travelMaster.rate:= 0
  218.     for obj in objList do
  219.         graphObject self obj duration:duration wait:true
  220.  
  221.     -- start the master clock which will start all the travelers travelling
  222.     self.travelMaster.rate:= 1
  223. )
  224.  
  225. method graphObject self {class Grapher} obj #key duration: wait:(false) ->
  226. (
  227.     local newX, newY, Xprop, Yprop, ivGetter, g
  228.     Xprop:= self.xAxis.property
  229.     Yprop:= self.yAxis.property
  230.     if Xprop <> undefined then
  231.     (
  232.         -- get the appropriate getter function for the instance variable that
  233.         -- corresponds to the axis property
  234.         ivGetter := Xprop.getterFn
  235.         newX:= self.xAxis.origin + (scaleValue self.xAxis Xprop (ivGetter obj)) -obj.tackPoint.x
  236.     ) else
  237.         newX:= self.xAxis.origin - obj.tackPoint.x
  238.         
  239.     if Yprop <> undefined then
  240.     (
  241.         ivGetter := Yprop.getterFn
  242.         newY:= self.yAxis.origin - (scaleValue self.yAxis Yprop (ivGetter obj)) -obj.tackPoint.y
  243.     ) else
  244.         newY:= self.yAxis.origin - obj.tackPoint.y    
  245.  
  246.     if duration = unsupplied do duration := self.travelDuration
  247.     travel obj (new Point x:newX y:newY) duration    
  248. )
  249.  
  250. -- For use of Tape Measure and other such parties
  251. method getScale self {class Grapher} ->
  252. (
  253.     local xprop, yprop
  254.     xprop:= self.xAxis.property
  255.     yprop:= self.yAxis.property
  256.     -- structure is an array where each item is a description of each dimension
  257.     -- where the description consists of the units of measurements and the 
  258.     -- pixels per unit conversion factor
  259.     #(#(xprop.units, self.xAxis.scale), #(yprop.units, self.yAxis.scale))
  260. )
  261.  
  262. method refreshGraph self {class Grapher} ->
  263. (
  264.     if (size self.objectList) > 0 do
  265.         graphObjects self self.objectList
  266.     
  267.     -- Notify other interested parties (e.g., the Tape Measure).
  268.     foreach self  ( item arg ->
  269.         (
  270.         if (canObjectDo item refreshGraph) do refreshGraph item
  271.         if (isDefined updateScale) and (canObjectDo item updateScale) do updateScale item
  272.         ) ) undefined
  273. )
  274.  
  275. --method startGraphing self {class Grapher} objList ->
  276. --(
  277. --    addObjectsToGraph self objList
  278. --    graphObjects self
  279. --)
  280.  
  281. "Compiled grapher.sx"
  282. -->>>
  283.